﻿using System;
using System.Text;
using NUnit.Framework;

namespace PropertyExpression.DynamicQueryStaticChecking.Test
{
    public class ConditionState
    {
        public bool Has { get; private set; }

        public void Add()
        {
            Has = true;
        }
    }

    public static class ConditionStateExtensions
    {
        public static Action Add(this ConditionState it, Action action)
        {
            return () =>
                       {
                           action();
                           it.Add();
                       };
        }
    }

    public partial class PreTextTemplate2
    {
        private readonly IInnerPartLinkSwitcher innerPartLinkSwitcher;
        public readonly IParamManager<PartLinkParams> Param;

        public PreTextTemplate2(IInnerPartLinkSwitcher innerPartLinkSwitcher, IParamManager<PartLinkParams> param)
        {
            this.innerPartLinkSwitcher = innerPartLinkSwitcher;
            Param = param;
        }
    }

    public interface IOptionalParamSwitter<TParam>
    {
        void AddSubQuery(Action action);
    }

    public class NotExistsOptionalParamSwitter<TParam> : IOptionalParamSwitter<TParam>
    {
        public void AddSubQuery(Action action)
        {
            //no-op
        }
    }

    public class ExistsOptionalParamSwitter<TParam> : IOptionalParamSwitter<TParam>
    {
        public readonly IParamManager<TParam> ParamManager;

        public ExistsOptionalParamSwitter(IParamManager<TParam> paramManager)
        {
            ParamManager = paramManager;
        }

        public void AddSubQuery(Action action)
        {
            action();
        }
    }

    public partial class PreTextTemplate1
    {
        private readonly IOptionalParamSwitter<PublicationCodeParam> publicationCodeSwitter;
        private readonly IOptionalParamSwitter<SppIdParam> sppIdSwitter;

        public PreTextTemplate1(
            IOptionalParamSwitter<PublicationCodeParam> publicationCodeSwitter,
            IOptionalParamSwitter<SppIdParam> sppIdSwitter)
        {
            this.publicationCodeSwitter = publicationCodeSwitter;
            this.sppIdSwitter = sppIdSwitter;
        }

        public bool NotEmpty
        {
            get
            {
                return GenerationEnvironment.Length > 0;
            }
        }
    }

    public class PublicationCodeParam
    {
    }

    public class SppIdParam
    {
    }

    [TestFixture]
    public class MainTest
    {
        [Test]
        public void Test50()
        {
            Console.WriteLine(new PreTextTemplate5().TransformText());
        }

        [Test]
        public void Test40()
        {
            Console.WriteLine(
                new PreTextTemplate1(
                    new NotExistsOptionalParamSwitter<PublicationCodeParam>(),
                    new NotExistsOptionalParamSwitter<SppIdParam>()
                    ).TransformText());
        }

        [Test]
        public void Test41()
        {
            var paramStringBuilder = new StringBuilder();

            Console.WriteLine(
                new PreTextTemplate1(
                    new ExistsOptionalParamSwitter<PublicationCodeParam>(
                        new StoredProceduresCreatingParamManager<PublicationCodeParam>(paramStringBuilder)
                        ),
                    new NotExistsOptionalParamSwitter<SppIdParam>()
                    ).TransformText());
        }

        [Test]
        public void Test42()
        {
            var paramStringBuilder = new StringBuilder();

            Console.WriteLine(
                new PreTextTemplate1(
                    new NotExistsOptionalParamSwitter<PublicationCodeParam>(),
                    new ExistsOptionalParamSwitter<SppIdParam>(
                        new StoredProceduresCreatingParamManager<SppIdParam>(paramStringBuilder)
                        )
                    ).TransformText());
        }

        [Test]
        public void Test43()
        {
            var paramStringBuilder = new StringBuilder();

            Console.WriteLine(
                new PreTextTemplate1(
                    new ExistsOptionalParamSwitter<PublicationCodeParam>(
                        new StoredProceduresCreatingParamManager<PublicationCodeParam>(paramStringBuilder)
                        ),
                    new ExistsOptionalParamSwitter<SppIdParam>(
                        new StoredProceduresCreatingParamManager<SppIdParam>(paramStringBuilder)
                        )
                    ).TransformText());
        }

        [Test]
        public void Test3()
        {
            var paramStringBuilder = new StringBuilder();

            var preTextTemplate2 = new PreTextTemplate2(
                new InnerPartLinkSwitcher(
                        new ActionSwitcher<NoParams>(new StoredProceduresCreatingParamManager<NoParams>(paramStringBuilder)),
                        new StoredProceduresCreatingParamManager<InnerPartLinkParams>(paramStringBuilder)
                        ),
                new StoredProceduresCreatingParamManager<PartLinkParams>(paramStringBuilder)
                );
            var transformText = preTextTemplate2.TransformText();

            Console.WriteLine(paramStringBuilder);

            Console.WriteLine(transformText);
        }

        [Test]
        public void Test5()
        {
            var paramStringBuilder = new StringBuilder();

            var preTextTemplate2 = new PreTextTemplate2(
                new InnerPartLinkSwitcher(
                        new NoActionSwitcher<NoParams>(),
                        new StoredProceduresCreatingParamManager<InnerPartLinkParams>(paramStringBuilder)
                        ),
                new StoredProceduresCreatingParamManager<PartLinkParams>(paramStringBuilder)
                );
            var transformText = preTextTemplate2.TransformText();

            Console.WriteLine(paramStringBuilder);

            Console.WriteLine(transformText);
        }

        [Test]
        public void Test6()
        {
            var paramStringBuilder = new StringBuilder();

            var preTextTemplate2 = new PreTextTemplate2(
                new NoInnerPartLinkSwitcher(),
                new StoredProceduresCreatingParamManager<PartLinkParams>(paramStringBuilder)
                );
            var transformText = preTextTemplate2.TransformText();

            Console.WriteLine(paramStringBuilder);

            Console.WriteLine(transformText);
        }
    }

    public class PartLinkParams
    {
        public readonly string PartList;
        public readonly Guid ModelPublicationID;
        public readonly Guid ServicePartsPageID;

        public PartLinkParams(string partList, Guid modelPublicationId, Guid servicePartsPageId)
        {
            PartList = partList;
            ModelPublicationID = modelPublicationId;
            ServicePartsPageID = servicePartsPageId;
        }
    }

    public static class PartLinkParamsPropertyExpressionExtension
    {
        public static string PartList(this IParamManager<PartLinkParams> it)
        {
            return it.Param(_ => _.PartList);
        }
        public static string ServicePartsPageID(this IParamManager<PartLinkParams> it)
        {
            return it.Param(_ => _.ServicePartsPageID);
        }
        public static string ModelPublicationID(this IParamManager<PartLinkParams> it)
        {
            return it.Param(_ => _.ModelPublicationID);
        }
    }

    public interface IInnerPartLinkSwitcher
    {
        void AddSubQuery(Action<IActionSwitcher<NoParams>> action);
    }

    public class NoInnerPartLinkSwitcher : IInnerPartLinkSwitcher
    {
        public void AddSubQuery(Action<IActionSwitcher<NoParams>> action)
        {
            //no-op
        }
    }

    public class InnerPartLinkSwitcher : IInnerPartLinkSwitcher
    {
        private readonly IActionSwitcher<NoParams> innerPartLinkSwitcher;
        public readonly IParamManager<InnerPartLinkParams> ParamManager;

        public InnerPartLinkSwitcher(IActionSwitcher<NoParams> innerPartLinkSwitcher, IParamManager<InnerPartLinkParams> paramManager)
        {
            this.innerPartLinkSwitcher = innerPartLinkSwitcher;
            ParamManager = paramManager;
        }

        public void AddSubQuery(Action<IActionSwitcher<NoParams>> action)
        {
            action(innerPartLinkSwitcher);
        }
    }

    public class InnerPartLinkParams
    {
        public readonly Guid ModelID;
        public readonly string LanguageCode;

        public InnerPartLinkParams(Guid modelID, string languageCode)
        {
            ModelID = modelID;
            LanguageCode = languageCode;
        }
    }

    public static class InnerPartLinkParamsPropertyExpressionExtension
    {
        public static string LanguageCode(this IParamManager<InnerPartLinkParams> it)
        {
            return it.Param(_ => _.LanguageCode);
        }
        public static string ModelID(this IParamManager<InnerPartLinkParams> it)
        {
            return it.Param(_ => _.ModelID);
        }
    }

    public class NoParams
    {        
    }

    public interface IActionSwitcher<TParams>
    {
        void AddSubQuery(Action action);
    }

    public class ActionSwitcher<TParams> : IActionSwitcher<TParams>
    {
        public readonly IParamManager<TParams> ParamManager;

        public ActionSwitcher(IParamManager<TParams> paramManager)
        {
            ParamManager = paramManager;
        }

        public void AddSubQuery(Action action)
        {
            action();
        }
    }

    public class NoActionSwitcher<TParams> : IActionSwitcher<TParams>
    {
        public void AddSubQuery(Action action)
        {
            //no-op
        }
    }
}